独習PHP:第6章 ユーザー定義の関数
5章のusort()で無名関数が解らないのでまずこっちから
ユーザー定義関数
PHPが提供していない、定型的な処理を開発者が自分で定義した関数
重複したコードが存在する場合、ユーザー定義関数で1箇所にまとめてしまうべき
命名について
動詞 + 名詞で定義することをお勧め
動詞は慣例的によく使用されるものを使っておくと良い
addTriangleAreaとか、setUserPersonalDataとか
checkUpdateDataとか、動詞を二つ繋げる形も良くない
名前で何ができるかを表してあげよう
initは、initialize(初期化)のことね
仮引数と実引数
引数
メソッドの中で参照可能な変数のこと
仮引数
受け取り側の変数のこと
関数の入り口
実引数
呼び出し元から渡される値
code:php
// 8, 10は実引数
getTriangleArea(8, 10);
// $base, $heightは仮引数。実引数が中に入っている
function getTriangleArea($base, $height) {
return $base * $height / 2;
}
一貫性について
checkDataとupdateDataという関数があったとして
code:php
function checkData($userId, $sex, $phoneNumber) { ...
function updateData($sex, $phoneNumber, $userId) { ...
似た関数であっても変数の並びに一貫性がないので、これも意識することが大事
戻り値
関数の出口のようなもの(入り口は仮引数)
戻り値がない関数は、nullを返すようになっている
code:php
function showMessage($name) {
print "こんにちは、{$name}さん";
}
$a = showMessage('武');
var_dump($a); // nullが格納されている
型宣言
code:php
// getTriangleArea(引数の型宣言, , ...) : 戻り値の型宣言 {
function getTriangleArea(float $base, float $height) : float {
return $base * $height / 2;
}
$area = getTriangleArea(100, 'x');
// Fatal error: Uncaught TypeError: getTriangleArea(): Argument #2 ($height) must be of type float, string given, called in .... 型を明示して、不正な型が渡されるのを未然に防ぐ。積極的に明示していくのが望ましい
複合的な型宣言
null許容型 (?int, $value) : nullもしくはint
Union型(PHP8.0のみ)
function calcNum(int | float $num) : float
|を使って、いずれかの型を指定することができる
false擬似型(PHP8.0のみ)
返り値に指定する function getA(, ,) : int|false:
関数が想像した挙動とならなかった時、falseを返す
voidについて
何も返さないということ
code:php
function hoge(): void {
return null; // nullのリターンを返してもvoidを指定しているのでnullは返ってこない
}
スクリプトの外部化
ユーザー定義関数は該当のページに書くよりも別ファイルとして保存しておく
必要に応じてインクルードするのが良い
require_once, include_onceなど
requireは指定ファイルがなかった場合はfatal errorを返す
includeはwarningを返すので処理自体は継続する
循環呼び出しに気を付ける
foo.phpというファイルがbar.phpというファイルを呼び
barがfooを呼んで...ということになる
なのでonce命令がお勧め
パスについて
絶対パスを推奨する
相対パスは起動したスクリプトが起点となるので、呼び出したファイルごとでエラーが起こるケースがある
require_once __DIR__.'/func1.php';と書いておくと良い
関数を定義する位置
どこに書いてもいいがチームルールがあれば従うのが良い
関数が定義されているか曖昧な場合はfunction_exists('functionName')関数などで調べるとよい
スコープ
グローバルスコープ
スクリプト全体から参照できる変数
関数やクラスは常にグローバルスコープ(同名の名前を定義することはできないということだよ)
$GLOBALSについて
全てのグローバル変数を管理する連想配列
code:php
function A(): int {
global $x;
$x = 100;
unset($GLOBALS'x'); // こんな感じで連想配列の中のものとして定義した値を取り使う ローカルスコープ
関数内でのみ定義できる変数
グローバルスコープと被った名前をつけても違う変数として見なされる
ローカルスコープ内で使いたい場合は、global命令を使う
code:php
$x = 10;
function addNum(): int {
global $x;
return ++$x;
}
static命令
ローカル変数は関数の処理が終了すると、情報が破棄される
static命令で静的変数にすることで、値を保持することができる
code:php
function checkStatic(): int {
static $x = 0;
return ++$x;
}
checkStatic(); // 1
chechStatic(); // 2
規定値
引数を省略した場合に規定で設定される値のこと
この引数は省略してもいいよ、ということを表したい時に使う
code:php
function getTriArea(float $base = 5, float $height = 1): float {
return $base * $height / 2;
}
getTriArea(); // 2.5
getTriArea(10, 2); // 10
引数の参照渡し
基本的に引数は値渡し
メモリの場所(アドレス)経由ではなく、数値として渡されるだけ
code:php
/* -- 値渡し -- */
function increment(int $num): int {
$num++;
return $num;
}
$value = 10;
print increment($value) . '<br>'; // 11 $valueの中の、10という数字をもらっているだけ
print $value . '<br>'; // 10 $valueの値が変わるわけではない
/* -- 参照渡ししてみる -- */
function increment(int &$num): int {
$num++;
return $num;
}
$value = 10;
print increment($value) . '<br>'; // 11
print $value . '<br>'; // 11
名前付き変数 8.0
code:php
// 通常省略すると規定値があれば、最初に引数に入るがこれはheightに入るようになる
print getTriangleArea(height: 10);
引数が多くなっても意味が把握しやすくなる
必要な引数だけをスマートに表現できる
引数の順序を自由に変更できるなど、便利
ただし
仮引数を変更すると呼び出し元も変更しなくてはいけなくなる
code:php
// $heightから$widthに変えた
function getTriangleArea(float $base = 5, float $width = 10): float {
....
// こっちも変えないとダメ
print getTriangleArea(height: 10);
可変長引数
...$valueで定義
引数の個数があらかじめ決まってない関数のこと
色々な数値の最大数を計算する関数などでよく使う
code:php
function total(float ...$args): float {
$result = 0;
foreach ($args as $arg) {
$result += $arg;
}
return $result;
}
print total(3, 10, -2, 1, 1, 5) . '<br>'; // 18
floatを型宣言し、可変長引数に指定しているが、全ての引数をこの定義に従わせる必要がある
可変長引数と通常の引数の混在
code:php
function replaceContents(string $path, string ...$args): string {
$data = file_get_contents($path);
for ($i = 0; $i < count($args); $i++) {
// str_replace(探したい値, 置き換える値, 検索対象の文字列)
$data = str_replace('{'.($i).'}', $args$i, $data); }
return $data;
}
echo replaceContents('data.dat', '鈴木', '2022年11月30日');
可変長引数は、引数リストの末尾に配置する
可変長引数は、0個以上の引数を表すので、何も指定していなくてもコードが通ってしまう
code:php
// こう書いておき、2つ目以降の引数を可変長引数として取り扱う方法もある
function total(float $init, float ...$args): float {
🌟argsの意味
argument(引数)というそのまんまの意味を複数形にしただけ
...演算子のアンパック
実引数で使用する。配列を個々の値に展開すること
code:php
function getTriangleArea(float $base, float $height) : float { ... }
// 0=>10, 1=>5の値が個々の値に展開され、$baseと$heightに入っている print getTriangleArea(...10,5); 複数の戻り値を出したい
return 1,2とかはできないので、配列やオブジェクトとして返す
再帰関数(Recursive Function)
関数が自分自身を呼び出すこと。同種の手続きを繰り返し呼び出すような処理を表す
code:php
// 再帰関数
function factorial(int $num): int {
if ($num !== 0) {
// $num * ($num - 1 * ($num - 1 - 1 * (...)))
// $num = 0になったら止まる
// $num - ($num - 1 と、ここでさらにfactorial()が呼ばれ、同じ処理が0になるまで入っていく)
// $num !== 0のifを取ったら永遠に呼ばれ続けてしまうため、メモリがオーバーフローする
return $num * factorial($num - 1);
}
return 1;
}
print factorial(6);
可変関数(Variable Functions)
$変数名()の形式で呼び出せる関数
変数名に応じて対応する関数を検索、実行することができる
code:php
$name = 'getTriangleArea';
// 関数名が変数の値で評価される
$area = $name(8, 10);
print $area;
どう使う?
高階関数として使ってみる
関数そのものを引数として渡したり、戻り値として返して使ったり
code:php
// 高階関数
// callable: コールバック関数であることの定義
function myArrayWalk(array $array, callable $func) : void {
foreach ($array as $key => $value) {
$func($value, $key);
}
}
// mixed: なんでも型OK
function showItem(mixed $value, int | string $key) : void {
print "{$key} : {$value}<br />";
}
myArrayWalk($data, 'showItem');
showItem()で行われている処理を
myArrayWalk()が繰り返し行なっているイメージ
code:php
// foreachで回したい関数その1
function showItem(mixed $value, int | string $key) : void {
print "{$key} : {$value}<br />";
}
// 回したい関数その2
$res = 0;
function total2(float $value, int $key) : void {
global $res;
$res += $value;
}
myArrayWalk($dt, 'total2');
print ($res);
myArrayWalk($data, 'showItem');
/*
165
0 : 杉山
1 : 永田
2 : 杉沼
3 : 和田
4 : 土井
*/
考え方
配列を操作する部分だけまず作成(myArrayWalk()部分)
詳細な機能は別途決めて設計する
関数のオブジェクト指向みたいな考え方だね
無名関数(クロージャ)
上のサンプルのshowItemなどはその場限りでしか使用しない、使い捨ての関数
関数をむやみやたらに作ると、名前が衝突する可能性が高まって面倒
code:php
/*
function(仮引数, ....) {
// 任意の処理
return 戻り値;
}
*/
function myArrayWalk(array $array, callable $func): void {
foreach($array as $key => $value) {
$func($value, $key);
}
}
// $funcの部分でクロージャとして呼び出す
myArrayWalk($data, function($value, $key) {
echo $key . ':' . $value . '<br>';
});
// 型宣言もできる
myArrayWalk($data, function(mixed $value, int | string $key): void { ...
use命令で親スコープから変数を引き継ぐ
code:php
$result = 0;
myArrayWalk($data,
// 外で定義した$resultを持ってくる
function($value, $key) use(&$result) {
$result += $value;
}
);
アロー関数で表す
functionがfnと呼ばれるようになったり、引数と関数を=>で接続するようになる
code:php
// function($x) { return $x * 2; }
$mul2 = fn($x) => $x * 2;
echo $mul2(3);
ジェネレーター
通常、関数はreturn命令で値を返したら終わり
yield命令を使うことで、その時々の値を返すことができるようになる
関数の結果を返すが、yieldは処理を一時停止させる
次呼び出された時、その時点から処理を再開させることができる
code:php
function myGen() {
yield 'アイウエオ';
yield 'かきくけこ';
yield 'さしすせそ';
}
foreach (myGen() as $val) {
print $val . '<br>';
}
/*
アイウエオ
かきくけこ
さしすせそ
*/
🌟明示的な型宣言
function myGen(): Generator { ... }